// 实现这个项目的构建任务
// watch监听文件变化
const { src, dest, parallel, series, watch } = require('gulp')
const browserSync = require('browser-sync') // 该模块可以提供一个开发服务器，可以实现热更新的插件，优点：当文件修改，自动热更新到浏览器
const loadPlugins = require('gulp-load-plugins') // 
const del = require('del')

const plugins = loadPlugins() // plugins是一个对象，所有的插件名都为该对象的一个属性
const bs = browserSync.create() // 创建一个开发服务器

let config = {
  build: {
    src: 'src',
    dist: 'dist',
    temp: 'temp',
    public: 'public',
    paths: {
      style: 'assets/styles/*.scss',
      scripts: 'assets/scripts/*.js',
      pages: '*.html',
      images: 'assets/images/**',
      fonts: 'assets/fonts/**'
    }
  }
} 

const cwd = process.cwd();
const loadConfig = require(`./pages.config.js`) // 注意require(`pages.config.js`)为什么不行， require语法
try{
  config = Object.assign({}, config, loadConfig)  // 获取的配置文件信息会会覆盖当前config的相同属性
}catch(e){
  throw Error(e)
}

const style = () => {
  return src(config.build.paths.style, { base: config.build.src, cwd: config.build.src}) // 指定cwd属性值，可以配置src的第一个路径从哪个目录开始往下找， 默认cwd是当前项目工作目录
  .pipe(plugins.sass({ outputStyle: 'expanded' }))
  .pipe(dest(config.build.temp))
  .pipe(bs.reload({ stream: true }))
}


const scripts = () => {
  return src(config.build.paths.scripts, { base: config.build.src, cwd: config.build.src })
  .pipe(plugins.babel({ presets:  ['@babel/preset-env'] }))
  .pipe(dest(config.build.temp))
  .pipe(bs.reload({ stream: true }))
}

const pages = () => {
  return src(config.build.paths.pages, { base: config.build.src, cwd: config.build.src })
  .pipe(plugins.swig({ data: config.data }))  // swig 用于模板编译
  .pipe(dest(config.build.temp))
  .pipe(bs.reload({ stream: true }))
}

const fonts = () => {
  return src(config.build.paths.fonts, { base: config.build.src, cwd: config.build.src })
  .pipe(plugins.imagemin()) // 压缩图片 二进制文件
  .pipe(dest(config.build.dist))
}

const images = () => {
  return src(config.build.paths.images, { base: config.build.src, cwd: config.build.src })
  .pipe(plugins.imagemin())
  .pipe(dest(config.build.dist))
}

const extra = () => {
  return src('**', { base: config.build.public, cwd: config.build.public })
  .pipe(dest(config.build.dist))
}

// 将.tmp目录下<!-- build:xxx> xxx </endbuild>下引用到的文件打包到生成一个新的文件
const useref = () => {
  return src(config.build.paths.pages, { base: config.build.temp, cwd: config.build.temp })
  .pipe(plugins.useref({ searchPath: ['.', '..'] }))
  // html js css
  .pipe(plugins.if(/\.js$/, plugins.uglify()))
  .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
  .pipe(plugins.if(/\.html$/, plugins.htmlmin({
    collapseWhitespace: true,
    minifyCSS: true,
    minifyJS: true
  })))
  .pipe(dest(config.build.dist))
}

// 清除文件
const clean = () => {
  return del([config.build.temp, config.build.dist])
}

// 开发服务器设置
const devServe = () => {
  watch(config.build.paths.style, { cwd: config.build.src }, style)
  watch(config.build.paths.scripts, { cwd: config.build.src }, scripts)
  watch(config.build.paths.pages, { cwd: config.build.src }, pages)
  watch([// bs.reload实现当images 或 fonts 文件更改时，浏览器重新请求该文件, 减少编译
    config.build.paths.images,
    config.build.paths.fonts,
  ],  { cwd: config.build.src }, bs.reload)
  watch('**', { cwd: config.build.public }, pages)  

  bs.init({
    notify: false, // 取消serve连接提示
    port: 8080, // 设置端口号
    // files: '.tmp/**', // 可以指定一个字符串
    server: {
      baseDir:[config.build.temp, config.build.src, config.build.public], // 先查询第一个数组第一个元素，找不到往数组后面查找
      routes: {
        '/node_modules' : 'node_modules'   // 路由映射
      }
    }
  })
}

const distServer = () => {
  bs.init({
    notify: false,
    port: 3323,
    server: config.build.dist
  })
}

const compile = parallel(style, scripts, pages)

// 上线之前的任务
const build = series(clean, parallel(series(compile, useref), images, fonts, extra)) 
// 开发的任务
const serve = series(compile, devServe) //串行任务
// 上线的任务
const start = series(build, distServer)
module.exports = {
  clean,
  build,
  serve,
  start,
}
